package com.googlecode.horncomb.web.spring.mvc;

import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class OutputStreamResponeController implements Controller,
		InitializingBean, ServletResponseStreamDelegate {
	String defaultContentType = "application/x-download";
	String defaultFileName = "noname";
	String filenameEncoding = "GBK";
	int readerBufferSiz = 4096;
	/** 是否是附件下载方式 */
	boolean attachment = true;

	private ServletResponeInputStreamProvider inputStreamProvider = null;

	public void afterPropertiesSet() throws Exception {
		Assert.notNull(this.inputStreamProvider,
				"the property responseStreamProvider must be not null");
	}

	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ServletResponeInputStreamSource fsr = this.inputStreamProvider
				.getInputStreamSource(request);
		this.createResponse(request, response, fsr);
		return null;
	}

	public void createResponse(HttpServletRequest request,
			HttpServletResponse response, ServletResponeInputStreamSource fsr)
			throws Exception {
		Assert.notNull(fsr, ServletResponeInputStreamProvider.class.getName()
				+ "getInputStreamSource() must be null");

		response.reset();

		String fn = fsr.getFileName();
		if (!StringUtils.hasText(fn)) {
			fn = this.defaultFileName;
		}
		if (attachment) {
			String encodedFilename = new String(fn
					.getBytes(this.filenameEncoding), "ISO8859-1");
			response.addHeader("Content-Disposition", "attachment; filename="
					+ encodedFilename);
		}
		String ct = fsr.getContentType() == null ? ct = request.getSession()
				.getServletContext().getMimeType(fn) : fsr.getContentType();
		if (!StringUtils.hasText(ct)) {
			ct = this.defaultContentType;
		}
		response.setContentType(ct);

		InputStream is = fsr.getInputStream();
		if (is != null) {
			OutputStream os = response.getOutputStream();
			try {
				byte[] buffer = new byte[readerBufferSiz];
				int bytesRead = 0;
				while ((bytesRead = is.read(buffer)) != -1) {
					os.write(buffer, 0, bytesRead);
				}
			} finally {
				if (is != null) {
					is.close();
				}
				if (os != null) {
					os.flush();
					os.close();
				}
			}
		}
	}

	/**
	 * @param servletResponeInputStreamProvider
	 *            the servletResponeInputStreamProvider to set
	 */
	public void setInputStreamProvider(
			ServletResponeInputStreamProvider inputStreamProvider) {
		this.inputStreamProvider = inputStreamProvider;
	}

	/**
	 * @param defaultContentType
	 *            the defaultContentType to set
	 */
	public void setDefaultContentType(String defaultContentType) {
		Assert.hasText(defaultContentType);
		this.defaultContentType = defaultContentType;
	}

	/**
	 * @param readerBufferSiz
	 *            the readerBufferSiz to set
	 */
	public void setReaderBufferSiz(int readerBufferSiz) {
		Assert.isTrue(readerBufferSiz > 0);
		this.readerBufferSiz = readerBufferSiz;
	}

	/**
	 * @param defaultFileName
	 *            the defaultFileName to set
	 */
	public void setDefaultFileName(String defaultFileName) {
		this.defaultFileName = defaultFileName;
	}

	/**
	 * @param attachment
	 *            the attachment to set
	 */
	public void setAttachment(boolean attachment) {
		this.attachment = attachment;
	}

	/**
	 * @param filenameEncoding
	 *            the filenameEncoding to set
	 */
	public void setFilenameEncoding(String filenameEncoding) {
		this.filenameEncoding = filenameEncoding;
	}
}
